# encoding=utf-8

"""IWebSocketClient.py

    定义websocket-client的行为
"""
import threading
import time
import traceback
import websocket
from websocket import WebSocketApp
from concurrent.futures.thread import ThreadPoolExecutor

from seg_common.Identity import UUIDTools
from seg_common.LoggingService import ConsoleService
from seg_common.LoggingService import ConsoleBuilder
from seg_system import ApplicationConfig


class IWebSocketClient:
    def __init__(self, uuid: str = None,
                 restart_second: int = 3,
                 **kwargs):
        # client识别号
        if uuid:
            self.uuid = uuid
        else:
            self.uuid = UUIDTools.get_uuid()

        # websocket链接地址
        self.connect_address = "ws://{}:{}/{}/{}".format(
            ApplicationConfig.WebSocketConfig.WS_IP,
            ApplicationConfig.WebSocketConfig.WS_PORT,
            ApplicationConfig.WebSocketConfig.WS_ROUTE,
            self.uuid
        )

        # ws链接实例
        self.ws = None

        # 连接次数
        self.reconnect_count = 0

        # 重启线程
        # self.future_obj = None
        # self.executor = ThreadPoolExecutor(max_workers=1)
        # self.lock = threading.Lock()

        # 日志
        self.log = ConsoleBuilder.get_logger("IWebSocketClient")

        # 重启时间
        self.restart_second = restart_second
        if int(self.restart_second) <= 0:
            self.restart_second = 3

    def start(self):
        websocket.enableTrace(True)

        self.ws = websocket.WebSocketApp(self.connect_address,
                                         on_message=self.msg_arrive_default,
                                         on_error=self.socket_error,
                                         on_close=self.disconnect,
                                         on_open=self.connect)

        try:
            self.ws.run_forever()
        except Exception as e:
            self.ws.close()

    def push(self, msg: dict, **kwargs):
        """
            主动触发的消息推送
        :param msg: 需要发送的dict信息，会被转换为json
        :return:
        """
        raise NotImplementedError

    def msg_arrive_default(self, ws: WebSocketApp, msg):
        """
            消息到达的常规处理方式
        :param ws:
        :param msg:
        :return:
        """
        raise NotImplementedError

    def get_connect_status(self):
        try:
            state = self.ws.sock.connected
            return state
        except Exception as e:
            # print(traceback.format_exc())
            return False

    def connect(self, ws: WebSocketApp):
        """
            链接成功的回调
        :param ws:
        :return:
        """
        self.reconnect_count = 0
        ConsoleService.console_log("WebSocket has connected to java, socket status: {}, uuid: {}".format(
            self.get_connect_status(), self.uuid
        ))

    def socket_error(self, ws: WebSocketApp, error):
        """
            websocket由于错误断开的事件

        :param ws:
        :param error:
        :return:
        """
        self.reconnect_count += 1

        self.log.warning(str(error))
        self.log.warning("Socket connected status: {}".format(self.get_connect_status()))
        self.log.warning("websocket reconnect...{}".format(self.reconnect_count))
        self.log.info("Connect restart in {}s later".format(self.restart_second))

        time.sleep(self.restart_second)
        self.start()

    def disconnect(self, ws: WebSocketApp):
        """
            主动断开链接后的回调
        :param ws:
        :return:
        """
        ConsoleService.console_log("Device websocket disconnect, uuid is: {}".format(self.uuid))

    # 守护线程部分编写失败，self.ws.run_forever是单独的线程，无法被主线程监控
    # def restart_thread(self):
    #     while True:
    #         try:
    #             self.start()
    #             break
    #         except Exception as e:
    #             print(traceback.format_exc())
    #             ConsoleService.console_log("websocket reconnect...{}".format(self.reconnect_count),
    #                                        ConsoleService.WARNING)
    #             time.sleep(2)
    #
    # def thread_callback(self, worker):
    #     worker_exception = worker.exception()
    #     if worker_exception:
    #         msg = 'Websocket Restart thread error occur: {}'.format(worker_exception)
    #         ConsoleService.console_log(msg, ConsoleService.EXCEPTION)
    #     else:
    #         ConsoleService.console_log("Websocket Restart success", ConsoleService.INFO)
    #
    # def reconnect(self):
    #     self.lock.acquire()
    #
    #     if self.future_obj is None or self.future_obj.done():
    #         self.future_obj = self.executor.submit(self.restart_thread)
    #         self.future_obj.add_done_callback(self.thread_callback)
    #
    #     self.lock.release()


# if __name__ == "__main__":
#     client = IWebSocketClient()
#     client.start()
